/**
	@file NounShipEnhancement.cpp

	(c)2006 Palestar Inc
	@author Richard Lyle @date 12/21/2008 5:29:55 PM
*/

#include "NounShip.h"
#include "GameContext.h"
#include "Network/LogClient.h"		// LogLevels
#include "VerbApplyEnhancement.h"
#include "DefaultLootTables.h"
#include "CargoEnhancement.h"
//---------------------------------------------------------------------------------------------------

float NounShip::enhancementModifier( NounEnhancement::System a_system, NounEnhancement::ModifierType a_modifier ) const
{
	return 1.0f + (((float)m_EnhancementTotals[a_system][a_modifier]) / 100.0f);
}


bool NounShip::canApplyEnhancement(CargoEnhancement *a_pEnhancement)
{
	// for now just make sure we have space.
	// TODO: Make sure this enhancement will attach to this ship
	if(enhancementCount() < maxEnhancements())
	{
		if(!a_pEnhancement->enhancement()->canApply(this))
			return false;
		// is this enhancement on this ship?
		if(a_pEnhancement->parent() == this)
			return true;
	}
	return false;
}
bool NounShip::applyEnhancement(CargoEnhancement *a_pEnhancement)
{
	if(canApplyEnhancement(a_pEnhancement))
	{
		Verb::Ref(new VerbApplyEnhancement(this, a_pEnhancement));
		return true;
	}
	return false;
}

int NounShip::enhancementCount() const
{
	int count = 0;
	for(int i=0;i<childCount();i++)
	{
		BaseNode * pChild = child(i);
		if ( WidgetCast<NounEnhancement>( pChild ) )
			count += 1;
	}

	return count;
}

// get this enhancement
inline 	NounEnhancement * NounShip::enhancement(int n)							
{
	int count = 0;
	for(int i=0;i<childCount();i++)
	{
		BaseNode * pChild = child(i);
		if ( WidgetCast<NounEnhancement>( pChild ) )
		{
			count += 1;
			if(count == n)
				return (NounEnhancement *)pChild;
		}
	}
	return NULL;
}



void NounShip::handleEnhancementDrops()
{
	// platforms do not drop enhancements
	if(type() == PLATFORM || type() == PLATFORM_SUPPLY)
		return;

	if(m_NounContext->dropCount() > 0)
	{
		// add up the chances for each drop
		int nTotalChance = 0;
		for(int i=0;i<m_NounContext->dropCount();i++)
		{
			NounContext::Drop *pDrop = m_NounContext->drop(i);
			if(pDrop)
				nTotalChance += pDrop->m_nChance;
		}

		// pick a random number between 0 and total chance
		int randomDrop = rand()%nTotalChance;

		int nTotal =0;
		NounContext::Drop *pSelectedDrop = NULL;
		// grab that drop
		for(int i=0;i<m_NounContext->dropCount();i++)
		{
			NounContext::Drop *pDrop = m_NounContext->drop(i);
			if(pDrop)
			{
				int nThisValue = nTotal+pDrop->m_nChance;
				if(randomDrop > nTotal && randomDrop < nThisValue)
				{
					pSelectedDrop = pDrop;
				}
				nTotal = nThisValue;
			}
		}
		// if we have a drop, dump it onto a cargo and put it into space
		if(pSelectedDrop)
		{
			CargoEnhancement::Ref pCargo = new CargoEnhancement( pSelectedDrop->m_nDropClassKey);
			Vector3 vPosition(0.0f);

			// assign loot
			if(pCargo.valid())
			{
				if(assignEnhancement(pCargo) == NULL)
					pCargo = NULL;
			}
		}
	}
	else
	{
		// this ship has no drops, so lets just use a default set of drops for now
		NounEnhancement *pEnh = NULL;
		ClassKey key = DefaultLootTables::GetRandomLoot(this);
		if(key != 0)
		{
			CargoEnhancement::Ref pCargo = new CargoEnhancement(key);
			Vector3 vPosition( 0.0f );
			if(pCargo.valid())
			{
				assignEnhancement(pCargo);
			}
		}
	}
}

// returns the ship that it was given too

NounShip * NounShip::assignEnhancement(CargoEnhancement *a_pCargo)
{
	// total amount of damage currently done to this ship, minus the slow drain
	long nTotal = 0;

	if(m_DamageList.size() == 0)
		return NULL;

	// first determine which ships could possibly get the loot
	std::list<NounShip *> potentialList;

	// add up the total stored damage
	for(DamageList::iterator iShip = m_DamageList.begin();iShip!=m_DamageList.end();++iShip)
	{
		DamageSource pSource = (*iShip);
		// dont count ai ships
		if(pSource.m_pSource->userId() != 0)
			nTotal += iShip->m_lDamage;
	}

	if(nTotal == 0)
		return NULL;

	for(DamageList::iterator iShip = m_DamageList.begin();iShip!=m_DamageList.end();++iShip)
	{
		DamageSource pSource = (*iShip);
		// if more than 5% of total damage add to potential list
		// dont count ai ships
		if(pSource.m_lDamage > (nTotal * 0.05f) && pSource.m_pSource->userId() != 0) 
			potentialList.push_back(iShip->m_pSource);
	}


	// if no potential targets no player ships were involved in the kill so dont drop anything
	if(potentialList.size() == 0)
	{
		return NULL;
	}

	// now pick a random ship to award the loot too
	NounShip * pSelectedShip = NULL;
	while(pSelectedShip == NULL)
	{
		// no possible ships can get this item, dump it into space
		// most likely this is because all original potential targets had full cargo holds
		if(potentialList.size() == 0)
		{
			Vector3 vPosition( worldPosition() + RandomVector( -radius(), radius() ) );
			vPosition.y = 0.0f;
			a_pCargo->setPosition( vPosition );
			a_pCargo->setTick( tick() );
			context()->attachNoun( a_pCargo );
			// let everyone int the area
			localChat( CharString().format( "Comms:<color;ffffff> No room in holds for  <color;%6.6x>%s</color></color>....",  a_pCargo->enhancement()->color().RGB(),a_pCargo->enhancement()->GetName()) );
			return NULL; 
		}

		// pick a random index from that list
		int selection = rand() % potentialList.size();
		int v = 0;
		// go through the list
		for(std::list<NounShip *>::iterator iShip = potentialList.begin();iShip!=potentialList.end();++iShip)
		{
			// is this the ship we want?
			if(selection==v)
			{
				// is there room on this ship for the new cargo?
				if((*iShip)->canAttachCargo(a_pCargo))
				{
					Noun * pHold = NounGame::findCargoHold( (*iShip), a_pCargo );
					if ( pHold != NULL )
					{
						Vector3 vLocalPosition( pHold->worldFrame() * ((*iShip)->worldPosition() - pHold->worldPosition()) );
						
						a_pCargo->setPosition( vLocalPosition );
						a_pCargo->setTick( tick() );
						// attach the child to the parent
						pHold->attachNode( a_pCargo );
						context()->user()->onLog( CharString().format("Enhancement:Spawn:%s[%s]",a_pCargo->enhancement()->GetName(),(*iShip)->name()),LOG_NORMAL );
						pSelectedShip = (*iShip);
					}
				}
				else
				{
					// we chose this ship, but it has no room. lets pick another one
					potentialList.erase(iShip);
					// go to end so we can try again
					iShip = potentialList.end();
				}
			}
			// next ship to test
			v++;
		}
	}

	// let everyone know who got the drop and who didnt 
	pSelectedShip->localChat( CharString().format( "Comms: <color;ffffff>%s receives <color;%6.6x>%s</color>...", pSelectedShip->name(), a_pCargo->enhancement()->color().RGB(), a_pCargo->enhancement()->GetName()) );
	return pSelectedShip;
}

// this is for dropping an enhancement into your cargo hold, used by admins to create
// items for test/rewards
bool NounShip::handleEnhancementDrop(CharString &a_className, ClassKey a_key/*=NULL_CLASS*/)
{
	int nCount = 0;

	Factory * pFactory = Factory::findFactory( a_key );
	if ( pFactory != NULL )
	{
		const char *name = pFactory->className();
		if(strstr(name,a_className))
		{
			NounEnhancement *pEnhancement = WidgetCast<NounEnhancement>( pFactory->createWidget() );
			if(pEnhancement)
			{
				CargoEnhancement::Ref pCargo = new CargoEnhancement( a_key);
				Vector3 vPosition( worldPosition() );
				vPosition.y = 0.0f;

				if(canAttachCargo(pCargo))
				{
					Noun * pHold = NounGame::findCargoHold( this, pCargo );
					if ( pHold != NULL )
					{
						Vector3 vLocalPosition( pHold->worldFrame() * (worldPosition() - pHold->worldPosition()) );
						
						pCargo->setPosition( vLocalPosition );
						pCargo->setTick( tick() );
						// attach the child to the parent
						pHold->attachNode( pCargo );
						context()->user()->onLog( CharString().format("Enhancement:Spawn:%s[%s]:[DEVSPAWN]",pCargo->enhancement()->GetName(),NounShip::name()),LOG_NORMAL );
						privateChat( CharString().format( "<color;ffffff>DEV: Creating <color;%6.6x>%s</color>",pCargo->enhancement()->color().RGB(),pCargo->enhancement()->GetName() ) );
						return true;
					}
				}

			}
		}

		int typeCount = Factory::typeCount( a_key );
		for(int i=0;i<typeCount;i++)
		{
			if(handleEnhancementDrop( a_className,Factory::type( a_key, i ) ) == true)
				return true;
		}
   }
	return false;
}


//---------------------------------------------------------------------------------------------------
//EOF
